package com.hougong.im.httpcontroller;

import com.baomidou.mybatisplus.toolkit.MapUtils;
import com.hougong.im.body.httpresponse.PersonMessageVo;
import com.hougong.im.body.notice.*;
import com.hougong.im.common.Constants;
import com.hougong.im.common.GlobalCode;
import com.hougong.im.entity.ChatUser;
import com.hougong.im.entity.GroupMessage;
import com.hougong.im.entity.Member;
import com.hougong.im.entity.PersonMessage;
import com.hougong.im.mapper.*;
import com.hougong.im.pool.ChatWithPool;
import com.hougong.im.pool.ConnPool;
import com.hougong.im.utils.*;
import io.netty.channel.Channel;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RestController
@RequestMapping("/message")
public class MessageController {
    private static final Logger LOGGER=LoggerFactory.getLogger(MessageController.class);
    private ExecutorService sendGroupExecutor = Executors.newFixedThreadPool(8);


    @Autowired
    private PersonMessageMapper personMessageMapper;
    @Autowired
    private ChatUserMapper chatUserMapper;
    @Autowired
    private ChatGroupMapper groupMapper;
    @Autowired
    private GroupMessageMemberMapper groupMessageMemberMapper;
    @Autowired
    private GroupMessageMapper groupMessageMapper;
    @Autowired
    private MemberMapper memberMapper;

    /**
     * 获取与朋友的 历史聊天记录
     * @param request
     * @return
     */
    @RequestMapping("/get_history_friend_message")
    public R getHistoryFriendMessage(HttpServletRequest request){
        String token = request.getParameter("token");
        Long currentUid=JwtUtils.getTokenUid(token);
        String fid = request.getParameter("fid");
        if(StringUtils.isBlank(fid)){
            return R.error("fid不存在");
        }

        Long fid_long=Long.valueOf(fid);
        List<PersonMessageVo> personMessages = personMessageMapper.selectHistoryFriendMessage(currentUid, fid_long);

        //记录当前和好友聊天
        ChatWithPool.setWithFriend(currentUid,fid_long);
        //设置好友的未读消息全部为已读
        personMessageMapper.setFriedMessageHasRead(currentUid,fid_long);
        return R.ok().put("history_friend_message",personMessages);
    }

    /**
     * 获取群消息
     * @param request
     * @return
     */
    @RequestMapping("/get_history_group_message")
    public R getHistoryGroupMessage(HttpServletRequest request){
        String token = request.getParameter("token");
        Long currentUid=JwtUtils.getTokenUid(token);
        String gid = request.getParameter("gid");
        Long gid_long=Long.valueOf(gid);
        List<Map> maps = groupMessageMapper.selectHistory(gid_long);
        return R.ok().put("groupMessageList",maps);
    }

    @RequestMapping("/send_group_message")
    public R sendGroupMessage(HttpServletRequest request){
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        ChatUser chatUser = chatUserMapper.selectById(currentUid);


        String gid = request.getParameter("gid");

        final Long gid_long=Long.valueOf(gid);
        String message = request.getParameter("message");
        //先插入数据库
        GroupMessage groupMessage=new GroupMessage();
        groupMessage.setGroupId(gid_long);
        groupMessage.setFromId(currentUid);
        groupMessage.setContent(message);
        groupMessage.setType(0);
        groupMessage.setCreteTime(new Date());
        groupMessageMapper.insert(groupMessage);
        //逐个发给群里的在线好友

        final GroupMessageNotice groupMessageNotice=new GroupMessageNotice();
        groupMessageNotice.setMid(groupMessage.getId());
        groupMessageNotice.setFromid(groupMessage.getFromId());
        groupMessageNotice.setUserName(chatUser.getUsername());
        groupMessageNotice.setUserNameLen(chatUser.getUsername().getBytes().length);
        groupMessageNotice.setAvatar(chatUser.getAvatar());
        groupMessageNotice.setAvatarLen(chatUser.getAvatar().getBytes().length);
        groupMessageNotice.setGid(groupMessage.getGroupId());
        groupMessageNotice.setMsg(groupMessage.getContent());
        groupMessageNotice.setMsgLen(groupMessage.getContent().getBytes().length);
        groupMessageNotice.setImageLen(0);
        groupMessageNotice.setImage("");
        groupMessageNotice.setType(groupMessage.getType());
        groupMessageNotice.setTimestamp(groupMessage.getCreteTime().getTime());

        sendGroupExecutor.submit(new Runnable() {
            @Override
            public void run() {
                Map<String,Object> map=new HashMap<>();
                map.put("group_id",gid_long);
                List<Member> members = memberMapper.selectByMap(map);
                Long memberId=null;
                for(Member member:members){
                    memberId = member.getMemberId();
                    Channel channel = ConnPool.queryTCP(memberId);
                    if(channel!=null && channel.isActive()){
                        SendUtils.sendNotice(channel,GlobalCode.Group_Message_Notice.getBizCode(),groupMessageNotice);
                    }
                }
            }
        });
        return R.ok();

    }


    /**
     * 发送好友消息
     * @param request
     * @return
     */
    @RequestMapping("/send_friend_message")
    public R sendFriendMessage(HttpServletRequest request){
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        String fid = request.getParameter("fid");
        Long fid_long=Long.valueOf(fid);
        String message = request.getParameter("message");
        Channel fChannel = ConnPool.queryTCP(fid_long);
        PersonMessage personMessage=new PersonMessage();
        personMessage.setFromId(currentUid);
        personMessage.setToId(fid_long);
        personMessage.setContent(message);
        personMessage.setCreateTime(new Date());
        //如果chatpool 当前用户没有和对方聊天 说明之前断网了，重新设置下
       ChatWithPool.setWithFriend(currentUid,fid_long);
        if(fChannel==null){
            personMessage.setReadStatus(0);
            personMessageMapper.insert(personMessage);
        }else {
            Long fChatTo = ChatWithPool.queryWithFriend(fid_long);
            if(fChatTo!=null && fChatTo.equals(currentUid)){
                //也在和我聊天
                personMessage.setReadStatus(1);
            }else {
                personMessage.setReadStatus(0);
            }
            personMessageMapper.insert(personMessage);
            //对方在线就发送消息
            FriendMessageNotice friendMessageNotice=new FriendMessageNotice();
            friendMessageNotice.setMid(personMessage.getId());
            friendMessageNotice.setFid(currentUid);   //用我的id 表示我发的
            String avatar = chatUserMapper.selectById(currentUid).getAvatar();
            friendMessageNotice.setHeadimg(avatar);
            friendMessageNotice.setHeadimgLen(avatar.getBytes().length);
            friendMessageNotice.setMsg(message);
            friendMessageNotice.setMsgLen(message.getBytes().length);
            friendMessageNotice.setImageLen(0);
            friendMessageNotice.setImage(null);
            friendMessageNotice.setType(0);
            friendMessageNotice.setTimestamp(personMessage.getCreateTime().getTime());
            SendUtils.sendNotice(fChannel,GlobalCode.Friend_Message_Notice.getBizCode(),friendMessageNotice);
        }
        return R.ok();
    }

    /**
     * 发送好友图片消息
     * @param file
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/send_friend_image")
    public R sendFriendImage(@RequestParam("image") MultipartFile file,HttpServletRequest request) throws IOException {
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        ChatUser chatUser = chatUserMapper.selectById(currentUid);
        String fid = request.getParameter("fid");
        Long fid_long=Long.valueOf(fid);
        String path = FileUtils.uploadPic(chatUser.getUsername(), file);
        PersonMessage personMessage=new PersonMessage();
        personMessage.setFromId(currentUid);
        personMessage.setToId(fid_long);
        personMessage.setImage(path);
        personMessage.setType(1);
        personMessage.setCreateTime(new Date());
        Channel fChannel = ConnPool.queryTCP(fid_long);
        ChatWithPool.setWithFriend(currentUid,fid_long);
        if(fChannel==null){
            personMessage.setReadStatus(0);
            personMessageMapper.insert(personMessage);
        }else {
            Long fChatTo = ChatWithPool.queryWithFriend(fid_long);
            if (fChatTo != null && fChatTo.equals(currentUid)) {
                //也在和我聊天
                personMessage.setReadStatus(1);
            } else {
                personMessage.setReadStatus(0);
            }
            personMessageMapper.insert(personMessage);
            FriendMessageNotice friendMessageNotice=new FriendMessageNotice();
            friendMessageNotice.setMid(personMessage.getId());
            friendMessageNotice.setFid(currentUid);   //用我的id 表示我发的
            String avatar = chatUser.getAvatar();
            friendMessageNotice.setHeadimg(avatar);
            friendMessageNotice.setHeadimgLen(avatar.getBytes().length);
            friendMessageNotice.setMsgLen(0);
            friendMessageNotice.setMsg(null);
            //图片
            friendMessageNotice.setImageLen(path.getBytes().length);
            friendMessageNotice.setImage(path);
            friendMessageNotice.setType(1);
            friendMessageNotice.setTimestamp(personMessage.getCreateTime().getTime());
            SendUtils.sendNotice(fChannel,GlobalCode.Friend_Message_Notice.getBizCode(),friendMessageNotice);
        }
        return R.ok();
    }

    /**
     * 申请建立和对方语音通话
     *
     * @param request
     * @return
     */
    @RequestMapping("/build_audio_chat")
    public R buildAudioChat(HttpServletRequest request) throws InterruptedException {
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        Long  fid = Long.valueOf(request.getParameter("fid"));
        InetSocketAddress udpAddress = ConnPool.queryUDP(currentUid);
        if(udpAddress==null){
            for(int i=0;i<3;i++){
                Thread.sleep(1000);
                udpAddress=ConnPool.queryUDP(currentUid);
                if(udpAddress!=null){
                    break;
                }
            }
        }
        if(udpAddress==null){
            return R.error("发起的客户端尚未建立起UDP服务器");
        }
        InetSocketAddress socketAddress = (InetSocketAddress)ConnPool.queryTCP(currentUid).remoteAddress();
        String ip = socketAddress.getAddress().getHostAddress();
        LOGGER.info("发起方申请建立语音连接，发起方UDP ip"+ip+"端口"+udpAddress.getPort());
        Channel fChannel = ConnPool.queryTCP(fid);
        ApplyAudioChatNotice applyAudioChatNotice=new ApplyAudioChatNotice();
        applyAudioChatNotice.setFid(currentUid);
        applyAudioChatNotice.setIp(ip);
        applyAudioChatNotice.setIpLen(ip.getBytes().length);
        applyAudioChatNotice.setPort(udpAddress.getPort());
        if(fChannel!=null){
            SendUtils.sendNotice(fChannel,GlobalCode.Apply_Audio_Chat_Notice.getBizCode(),applyAudioChatNotice);
        }else {
            //如果对方不在线，需要一个超时的任务，去探测对方是否在线,，每隔2秒查询一次，总共执行60次，当超过60次就结束，或者对方一上线也结束
            LOGGER.warn("对方不在线，进入一个定时任务");
            return R.error("对方不在线！！稍后再通话");
        }
        return R.ok();
    }

    /**
     * 接受请求 ，则服务器把当前任的Ip port发送给对方
     * @param request
     * @return
     */
    @RequestMapping("/accept_audio_chat")
    public R acceptAudioChat(HttpServletRequest request) throws InterruptedException {
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        Long  fid = Long.valueOf(request.getParameter("fid"));
        InetSocketAddress udpAddress = ConnPool.queryUDP(currentUid);
        if(udpAddress==null){
            for(int i=0;i<3;i++){
                Thread.sleep(1000);
                udpAddress=ConnPool.queryUDP(currentUid);
                if(udpAddress!=null){
                    break;
                }
            }
        }
        if(udpAddress==null){
            return R.error("发起的客户端尚未建立起UDP服务器");
        }
        InetSocketAddress socketAddress = (InetSocketAddress)ConnPool.queryTCP(currentUid).remoteAddress();
        String ip = socketAddress.getAddress().getHostAddress();
        LOGGER.info("接受方接受建立语音连接，接受方UDP ip"+ip+"端口"+udpAddress.getPort());

        AcceptAudioChatNotice acceptAudioChatNotice=new AcceptAudioChatNotice();
        acceptAudioChatNotice.setFid(currentUid);
        acceptAudioChatNotice.setIp(ip);
        acceptAudioChatNotice.setIpLen(ip.getBytes().length);
        acceptAudioChatNotice.setPort(udpAddress.getPort());

        Channel fChannel = ConnPool.queryTCP(fid);
        if(fChannel!=null){
            SendUtils.sendNotice(fChannel,GlobalCode.Accept_Audio_Chat_Notice.getBizCode(),acceptAudioChatNotice);
        }else {
            LOGGER.warn("对方已经离线!====》fid:"+fid);
            return R.error("对方已经离线!");
        }
        return R.ok();
    }

    /**
     * 关闭通话
     * @param request
     * @return
     */
    @RequestMapping("/close_audio_chat")
    public R closeAudioChat(HttpServletRequest request){
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        Long  fid = Long.valueOf(request.getParameter("fid"));
        ConnPool.removeUDP(fid);
        ConnPool.removeUDP(currentUid);
        Channel query = ConnPool.queryTCP(fid);
        if(query!=null){
            CloseAudioChatNotice closeAudioChatNotice=new CloseAudioChatNotice();
            closeAudioChatNotice.setFid(currentUid);
            SendUtils.sendNotice(query,GlobalCode.Close_Audio_Chat_Notice.getBizCode(),closeAudioChatNotice);
            return R.ok();
        }
        return R.ok();
    }



    /**
     * 设置退出与这一个好友聊天
     * @param request
     * @return
     */
    @RequestMapping("/not_in_chatting_friend")
    public R setNotChatWithFriend(HttpServletRequest request){
        System.out.println("进入  /not_in_chatting_friend");
        String token = request.getParameter("token");
        Long currentUid = JwtUtils.getTokenUid(token);
        String fid = request.getParameter("fid");
        Long fid_long = Long.valueOf(fid);
        ChatWithPool.removeWithFriend(currentUid,fid_long);
        return R.ok();
    }

    @RequestMapping(value="/upload",method=RequestMethod.POST)
    public R upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
        String fileName = DateUtils.format(new Date(),"yyyyMMddHHmmss") +"_"+file.getOriginalFilename();
        File dir = new File(Constants.Upload_Path_Dir,fileName);
        if(!dir.getParentFile().exists()){
            dir.getParentFile().mkdirs();
        }
        file.transferTo(dir);
        System.out.println("fileName"+fileName);
        return R.ok();
    }

    @RequestMapping("/down")
    public void down(HttpServletRequest request,HttpServletResponse response) throws Exception{

        String fileName = request.getSession().getServletContext().getRealPath("upload")+"/101.jpg";

        InputStream bis = new BufferedInputStream(new FileInputStream(new File(fileName)));

        String filename = "下载文件.jpg";

        filename = URLEncoder.encode(filename,"UTF-8");

        response.addHeader("Content-Disposition", "attachment;filename=" + filename);

        response.setContentType("multipart/form-data");

        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        int len = 0;
        while((len = bis.read()) != -1){
            out.write(len);
            out.flush();
        }
        out.close();
    }
}
